﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;

namespace MetaDemo.Tabs
{
    public partial class ObjectProperties : UserControl
    {
        public static TabPage Get(Object o)
        {
            // Display information on the object.
            var props = new ObjectProperties();

            props.grdProperties.DataError += new DataGridViewDataErrorEventHandler(props.grdProperties_DataError);
            props.grdProperties.AutoGenerateColumns = false;

            // Bind the fields to the columns
            var bs = new BindingSource();
            bs.DataSource = PropertyInstance.GetInstances(o);
            props.grdProperties.DataSource = bs;

            // Create a tab page in which to display the information above.
            var page = GetTabPage();
            page.Controls.Add(props);

            return page;
        }

        public static TabPage GetTabPage()
        {
            var page = new TabPage();

            page.Location = new System.Drawing.Point(4, 22);
            page.Name = "tabProperties";
            page.Padding = new System.Windows.Forms.Padding(3);
            page.Size = new System.Drawing.Size(428, 391);
            page.Text = "Properties";
            page.UseVisualStyleBackColor = true;

            return page;
        }

 
        
        public ObjectProperties()
        {
            InitializeComponent();
        }

        #region datagrid handler

        private void grdProperties_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            DataGridView view = sender as DataGridView;
            if (0 == e.ColumnIndex)
            {
                // Name link has been clicked: Forward navigation to the property value object!
                var propInstance = (PropertyInstance)view.Rows[e.RowIndex].DataBoundItem;

                if (null == propInstance.Info.GetGetMethod())
                {
                    MessageBox.Show("Cannot display info for property value, if there is not getter.");
                    return;
                }

                if (0 < propInstance.Info.GetIndexParameters().Count())
                {
                    MessageBox.Show("Cannot display info for index property: there is no single value object.");
                    return;
                }
                    
                Object value = null;
                try { value = propInstance.Value; }
                catch (Exception)
                {
                    MessageBox.Show("Cannot retrieve value.");
                    return;
                }

                if (null == value)
                {
                    MessageBox.Show("Cannot display info for <null> object.");
                    return;
                }

                Forms.ObjectInfoForm.Get(propInstance.Value).Show();
            }
            if (3 == e.ColumnIndex)
            {
                // Type has been clicked: Forward navigation to the field's type object!
                var propInstance = (PropertyInstance)view.Rows[e.RowIndex].DataBoundItem;
                Forms.ObjectInfoForm.Get(propInstance.Type).Show();
            }
        }

        private void grdProperties_DataError(object sender, DataGridViewDataErrorEventArgs args)
        {
            throw args.Exception;
        }

        #endregion
    }






    public class PropertyInstance
    {
        public static List<PropertyInstance> GetInstances(Object obj)
        {
            List<PropertyInstance> list = new List<PropertyInstance>();

            // Fields
            var properties = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
            foreach (PropertyInfo pi in properties)
            {
                list.Add(new PropertyInstance(obj, pi));
            }

            return list;
        }


        private Object parent;
        private PropertyInfo propInfo;

        public PropertyInstance(Object p, PropertyInfo fi)
        {
            parent = p;
            propInfo = fi;
        }

        public PropertyInfo Info { get { return propInfo; } }

        public String PropertyName { get { return propInfo.Name; } }

        public String PropertyType { get { return propInfo.PropertyType.ToString(); } }

        public String PropertyAccessibility
        {
            get
            {
                String v = "";
                v += (null == propInfo.GetGetMethod()) ? "-" : "GET";
                v += " / ";
                v += (null == propInfo.GetSetMethod()) ? "-" : "SET";
                return v;
            }
        }

        public String PropertyValue
        {
            get
            {
                if (null == propInfo.GetGetMethod())
                    return "<not accessible>";

                if (0 < propInfo.GetIndexParameters().Count())
                    return "<cannot access array>";

                try
                {
                    var v = Value;
                    return (null == v) ? "null" : v.ToString();
                }
                catch (Exception e)
                {
                    return "<not retrievable>";
                }

            }
            set
            {
                try
                {
                    MetaHelper.SetMember(propInfo, parent, value);
                }
                catch (ReflectionException e)
                {
                    MessageBox.Show(e.Message);
                }
            }
        }

        public Type Type { get { return propInfo.PropertyType; } }

        public Object Value
        {
            get
            {
                var m = propInfo.GetGetMethod();
                if (null == m)
                    throw new ReflectionException("Cannot retrieve property value - no getter!");

                if (0 != m.GetParameters().Count())
                    return null;

                return propInfo.GetValue(parent, null);
            }
        }
    }

}
